/**
 ******************************************************************************
 * @file    app_core.c
 * @author  Lucien
 * @version V1.0.0
 * @date    2025-08-22
 * @brief   Implementation of application core:
 *          - Message queue (app_msg)
 *          - Software timer (app_timer)
 *          - System initialization (app_core_init)
 ******************************************************************************
 * @attention
 * This software is provided "AS IS", without any warranty.
 ******************************************************************************
 */

#include "app_core.h"
#include "stm32_timer.h"
#include "stm32wbaxx_hal.h"
#include <string.h>

/* ----------------------------
   Constants
-----------------------------*/
#ifndef TIMERTIME_T_MAX
#define TIMERTIME_T_MAX ((uint32_t)~0)
#endif

#define APP_MSG_NUM 100u

/* ----------------------------
   Internal types for message queue
-----------------------------*/
typedef struct {
    msg_handler_t handler; /**< Message handler function */
    void *param;           /**< Message argument */
} msg_t;

typedef struct {
    msg_t *osq_start;
    msg_t *osq_end;
    msg_t *osq_in;
    msg_t *osq_out;
    uint16_t osq_size;
    uint16_t osq_entries;
} OS_Q;

typedef struct {
    OS_Q q_msg;
    msg_t *msgGrp;
} queue_msg_t;

/* ----------------------------
   Module variables
-----------------------------*/
static queue_msg_t app_msg;             /**< Application message queue */
static msg_t _msg_app_grp[APP_MSG_NUM]; /**< Message storage */
static uint8_t app_msg_inited = 0;
static uint8_t system_inited = 0;

/* ----------------------------
   Internal message queue functions
-----------------------------*/
static void msg_init(queue_msg_t *msg_head, msg_t *msgGrp, uint16_t grp_size)
{
    if (!msg_head || !msgGrp) return;

    OS_Q *pq = &msg_head->q_msg;
    msg_head->msgGrp = msgGrp;
    pq->osq_start = msgGrp;
    pq->osq_end = msgGrp + grp_size;
    pq->osq_in = msgGrp;
    pq->osq_out = msgGrp;
    pq->osq_entries = 0u;
    pq->osq_size = grp_size;
}

static uint16_t msg_post_internal(queue_msg_t *msg_head, msg_handler_t handler, void *arg, uint8_t front)
{
    OS_Q *pq = &msg_head->q_msg;
    if (!handler) return 1; /* Invalid parameter */
    if (pq->osq_entries >= pq->osq_size) return 2; /* Queue full */

    if (front)
    {
        if (pq->osq_out == pq->osq_start) pq->osq_out = pq->osq_end;
        pq->osq_out--;
        pq->osq_out->handler = handler;
        pq->osq_out->param = arg;
    }
    else
    {
        pq->osq_in->handler = handler;
        pq->osq_in->param = arg;
        pq->osq_in++;
        if (pq->osq_in == pq->osq_end) pq->osq_in = pq->osq_start;
    }

    pq->osq_entries++;
    return 0;
}

static uint16_t msg_post_accept(queue_msg_t *msg_head, msg_t *pmsg)
{
    OS_Q *pq = &msg_head->q_msg;
    if (pq->osq_entries == 0) return 1; /* Queue empty */

    *pmsg = *(pq->osq_out);
    pq->osq_out++;
    if (pq->osq_out == pq->osq_end) pq->osq_out = pq->osq_start;
    pq->osq_entries--;
    return 0;
}

static void app_msg_process(void)
{
    while (1)
    {
        msg_t msg;
        if (msg_post_accept(&app_msg, &msg) == 0)
        {
            if (msg.handler) msg.handler(msg.param);
        }
        else break;
    }
}

/* ----------------------------
   Public message queue APIs
-----------------------------*/
void app_msg_init(void)
{
    if (app_msg_inited) return;
    msg_init(&app_msg, _msg_app_grp, APP_MSG_NUM);
    app_msg_inited = 1;
}

void app_core_init(void)
{
    if (system_inited) return;
    app_msg_init();
    system_inited = 1;
}

void app_core_process(void)
{
  app_msg_process();
}



uint16_t app_msg_post(msg_handler_t handler, void *arg)
{
    return msg_post_internal(&app_msg, handler, arg, 0);
}

uint16_t app_msg_post_front(msg_handler_t handler, void *arg)
{
    return msg_post_internal(&app_msg, handler, arg, 1);
}

/* ----------------------------
   Timer internal callback
   ISR safe: only posts a message to queue
-----------------------------*/
static void app_timer_internal_callback(void *arg)
{
    if (!arg) return;
    app_timer_t *timer = (app_timer_t *)arg;
    app_msg_post(app_timer_process, timer);
}

/* ----------------------------
   Public timer APIs
-----------------------------*/
void app_timer_init(app_timer_t *timer, msg_handler_t cb, void *arg, uint32_t period_ms, uint8_t repeat)
{
    timer->user_cb = cb;
    timer->user_arg = arg;
    timer->period_ms = period_ms;
    timer->repeat = repeat;

    UTIL_TIMER_Create(&timer->util_timer,
                      TIMERTIME_T_MAX,
                      UTIL_TIMER_ONESHOT,
                      app_timer_internal_callback,
                      (void *)timer);
}

void app_timer_start(app_timer_t *timer)
{
    UTIL_TIMER_SetPeriod(&timer->util_timer, timer->period_ms);
    UTIL_TIMER_Start(&timer->util_timer);
}

void app_timer_stop(app_timer_t *timer)
{
    UTIL_TIMER_Stop(&timer->util_timer);
}

void app_timer_process(void *arg)
{
    if (!arg) return;
    app_timer_t *timer = (app_timer_t *)arg;

    if (timer->user_cb) timer->user_cb(timer->user_arg);

    if (timer->repeat) app_timer_start(timer);
}



